package com.codeoss.framework.report.util;


import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.codeoss.framework.context.YunContext;
import com.codeoss.framework.data.metadata.Column;
import com.codeoss.framework.data.metadata.Query;
import com.codeoss.framework.data.metadata.Restrictions;
import com.codeoss.framework.data.metadata.Table;
import com.codeoss.framework.data.metadata.TableData;
import com.codeoss.framework.data.store.ITableStore;
import com.codeoss.framework.expression.Expression;
import com.codeoss.framework.expression.ExpressionUtil;
import com.codeoss.framework.expression.JavaScriptScriptService;
import com.codeoss.framework.report.def.ReportDataItemDef;
import com.codeoss.framework.report.def.SummaryReport;
import com.codeoss.framework.util.LookupInfo;
import com.codeoss.framework.util.StringUtils;
import com.codeoss.framework.view.component.IDataBinding;
import com.codeoss.framework.view.component.IVarName;
import com.codeoss.framework.view.component.Page;
import com.codeoss.framework.view.datasource.DataSourceConfig;
import com.codeoss.framework.view.datasource.IDataSource;
import com.codeoss.framework.view.datasource.store.IDataSourceStore;
import com.codeoss.framework.view.model.SelectItem;
import com.codeoss.framework.view.service.IVariableService;
import com.codeoss.framework.view.util.LookupUtil;
import com.codeoss.module.ir.model.IrReport;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
@Component
public class SummaryReportUtil {
	@Autowired
	private ObjectMapper objectMapper;
	@Autowired
	private JavaScriptScriptService javaScriptScriptService;
	@Autowired
	private ITableStore tableStore;
	@Autowired
	private IDataSourceStore dataSourceStore;
	@Autowired
	private LookupUtil lookupUtil;
	@Autowired
	private IVariableService variableService;
	public SummaryReport buildSummaryReportFromJson(String json) {
		ObjectNode objectNode = null;
		try {
			objectNode = (ObjectNode) objectMapper.readTree(json);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			throw new RuntimeException(e);
		}
		SummaryReport summaryReport=new SummaryReport();
		DataSourceConfig dataSourceConfig = buildDataSourceConfig(objectNode);
		summaryReport.setDataSourceConfig(dataSourceConfig);
		
		ArrayNode dimensionRowListArrayNode = (ArrayNode) objectNode.get("summaryReportConfigPage").get("dimensionRowList");
		ArrayNode dimensionColListArrayNode = (ArrayNode) objectNode.get("summaryReportConfigPage").get("dimensionColList");
		ArrayNode measureListArrayNode = (ArrayNode) objectNode.get("summaryReportConfigPage").get("measureList");
		
		List<ReportDataItemDef> dimensionRowList=new ArrayList<ReportDataItemDef>();
		List<ReportDataItemDef> dimensionColList=new ArrayList<ReportDataItemDef>();
		List<ReportDataItemDef> measureList=new ArrayList<ReportDataItemDef>();
		summaryReport.setDimensionRowList(dimensionRowList);
		summaryReport.setDimensionColList(dimensionColList);
		summaryReport.setMeasureList(measureList);
		for(int i=0;i<dimensionRowListArrayNode.size();i++) {
			ObjectNode dimensionRowObjectNode=(ObjectNode)dimensionRowListArrayNode.get(i);
			ReportDataItemDef reportDataItemDef=parseReportDataItemDefObjectNode(dimensionRowObjectNode);
			dimensionRowList.add(reportDataItemDef);
		}
		for(int i=0;i<dimensionColListArrayNode.size();i++) {
			ObjectNode dimensionColObjectNode=(ObjectNode)dimensionColListArrayNode.get(i);
			ReportDataItemDef reportDataItemDef=parseReportDataItemDefObjectNode(dimensionColObjectNode);
			dimensionColList.add(reportDataItemDef);
		}
		for(int i=0;i<measureListArrayNode.size();i++) {
			ObjectNode measureObjectNode=(ObjectNode)measureListArrayNode.get(i);
			ReportDataItemDef reportDataItemDef=parseReportDataItemDefObjectNode(measureObjectNode);
			measureList.add(reportDataItemDef);
		}
		return summaryReport;
	}
	
	public SummaryReport buildSummaryReportFromIrReport(IrReport irReport) {
		String jsonContext=irReport.getJsonContent();
		if(!StringUtils.isEmpty(jsonContext)) {
			try {
				SummaryReport summaryReport=objectMapper.readValue(jsonContext, SummaryReport.class);
				return summaryReport;
			} catch (Exception e) {
				// TODO Auto-generated catch block
				throw new RuntimeException(e);
			}
		}
		return null;
	}
	
	public SummaryReportModel buildSummaryReportData(SummaryReport summaryReport) {
		YunContext yunContext = YunContext.getCurrentContext();
		TableData tableData = getTableData(yunContext, summaryReport);
		if(tableData.getTotal()==0) {
			return null;
		}
		if(summaryReport.getDimensionColList().size()==0) {
			SummaryReportModel summaryReportModel=getGroupReportData(yunContext,summaryReport,tableData.getData());
			return summaryReportModel;
		}else if(summaryReport.getDimensionColList().size()>0) {
			SummaryReportModel summaryReportModel=getSummaryReportData(yunContext,summaryReport,tableData.getData());
			return summaryReportModel;
		}
		return null;
	}
	private SummaryReportModel  getSummaryReportData(YunContext yunContext,SummaryReport summaryReport,List<Map<String,Object>> dataList){
		List<List<Object>> returnList=new ArrayList<List<Object>>();
		List<List<Object>> dimensionRowValueListList=new ArrayList<List<Object>>();
		List<List<Object>> dimensionColValueListList=new ArrayList<List<Object>>();
		List<Map<String,BigDecimal>> measureMapList=new ArrayList<Map<String,BigDecimal>>();
		List<Map<String,Long>> measureLengthMapList=new ArrayList<Map<String,Long>>();
		List<ReportDataItemDef> dimensionRowList=summaryReport.getDimensionRowList();
		List<ReportDataItemDef> dimensionColList=summaryReport.getDimensionColList();
		for(int i=0;i<dimensionRowList.size();i++) {
			dimensionRowValueListList.add(new ArrayList<Object>());
		}
		for(int i=0;i<dimensionColList.size();i++) {
			dimensionColValueListList.add(new ArrayList<Object>());
		}
		List<ReportDataItemDef> measureList=summaryReport.getMeasureList();
		for(int i=0;i<measureList.size();i++) {
			measureMapList.add(new HashMap<String,BigDecimal>());
			measureLengthMapList.add(new HashMap<String,Long>());
		}
		for(int i=0;i<dataList.size();i++) {
			Map<String,Object> dataMap=dataList.get(i);
			StringBuilder dimensionKeyBuilder=new StringBuilder();
			for(int j=0;j<dimensionRowList.size();j++) {
				if (j > 0) {
					dimensionKeyBuilder.append("::");
				}
				ReportDataItemDef reportDataItemDef=dimensionRowList.get(j);
				String field=reportDataItemDef.getField();
				Object dimensionValue=dataMap.get(field);
				String fieldExtra = reportDataItemDef.getFieldExtra();
				if (!StringUtils.isJsonEmpty(fieldExtra)) {
					Date dateValue = (Date) dimensionValue;
					if ("year".equals(fieldExtra)) {
						dimensionValue = new SimpleDateFormat("yyyy年").format(dateValue);
					} else if ("quarter".equals(fieldExtra)) {
						Calendar calendar = Calendar.getInstance();
						calendar.setTime(dateValue);
						StringBuilder dimensionValueBuilder = new StringBuilder();
						int year = calendar.get(Calendar.YEAR);
						dimensionValueBuilder.append(year);
						dimensionValueBuilder.append("年");
						int month = calendar.get(Calendar.MONTH);
						if (month >= 0 && month <= 2) {
							dimensionValueBuilder.append("第一季度");
						} else if (month >= 3 && month <= 5) {
							dimensionValueBuilder.append("第二季度");
						} else if (month >= 6 && month <= 8) {
							dimensionValueBuilder.append("第三季度");
						} else if (month >= 9 && month <= 11) {
							dimensionValueBuilder.append("第四季度");
						}
						dimensionValue = dimensionValueBuilder.toString();
					} else if ("month".equals(fieldExtra)) {
						dimensionValue = new SimpleDateFormat("yyyy年MM月").format(dateValue);
					} else if ("day".equals(fieldExtra)) {
						dimensionValue = new SimpleDateFormat("yyyy-MM-dd").format(dateValue);
					}
				}
				dimensionKeyBuilder.append(dimensionValue);
				List<Object> dimensionRowValueList = dimensionRowValueListList.get(j);
				if (!dimensionRowValueList.contains(dimensionValue)) {
					dimensionRowValueList.add(dimensionValue);
				}
			}
			for(int j=0;j<dimensionColList.size();j++) {
			    dimensionKeyBuilder.append("::");
				
				ReportDataItemDef reportDataItemDef=dimensionColList.get(j);
				String field=reportDataItemDef.getField();
				Object dimensionValue=dataMap.get(field);
				String fieldExtra = reportDataItemDef.getFieldExtra();
				if (!StringUtils.isJsonEmpty(fieldExtra)) {
					Date dateValue = (Date) dimensionValue;
					if ("year".equals(fieldExtra)) {
						dimensionValue = new SimpleDateFormat("yyyy年").format(dateValue);
					} else if ("quarter".equals(fieldExtra)) {
						Calendar calendar = Calendar.getInstance();
						calendar.setTime(dateValue);
						StringBuilder dimensionValueBuilder = new StringBuilder();
						int year = calendar.get(Calendar.YEAR);
						dimensionValueBuilder.append(year);
						dimensionValueBuilder.append("年");
						int month = calendar.get(Calendar.MONTH);
						if (month >= 0 && month <= 2) {
							dimensionValueBuilder.append("第一季度");
						} else if (month >= 3 && month <= 5) {
							dimensionValueBuilder.append("第二季度");
						} else if (month >= 6 && month <= 8) {
							dimensionValueBuilder.append("第三季度");
						} else if (month >= 9 && month <= 11) {
							dimensionValueBuilder.append("第四季度");
						}
						dimensionValue = dimensionValueBuilder.toString();
					} else if ("month".equals(fieldExtra)) {
						dimensionValue = new SimpleDateFormat("yyyy年MM月").format(dateValue);
					} else if ("day".equals(fieldExtra)) {
						dimensionValue = new SimpleDateFormat("yyyy-MM-dd").format(dateValue);
					}
				}
				dimensionKeyBuilder.append(dimensionValue);
				List<Object> dimensionColValueList = dimensionColValueListList.get(j);
				if (!dimensionColValueList.contains(dimensionValue)) {
					dimensionColValueList.add(dimensionValue);
				}
			}
			String dimensionKey=dimensionKeyBuilder.toString();
			for(int k=0;k<measureList.size();k++) {
				ReportDataItemDef reportDataItemDef=measureList.get(k);
				String measureField = reportDataItemDef.getField();
				Object measureValue = dataMap.get(measureField);
				String aggregateType = reportDataItemDef.getAggregateType();
				Map<String,BigDecimal> measureMap=measureMapList.get(k);
				BigDecimal fieldValue = measureMap.get(dimensionKey);
				if ("sum".equals(aggregateType)) {
					if (fieldValue == null) {
						fieldValue = new BigDecimal(0);
					}
					fieldValue = fieldValue.add(new BigDecimal(measureValue + ""));
					measureMap.put(dimensionKey, fieldValue);
				} else if ("average".equals(aggregateType)) {
					if (fieldValue == null) {
						fieldValue = new BigDecimal(0);
					}
					fieldValue = fieldValue.add(new BigDecimal(measureValue + ""));
					measureMap.put(dimensionKey, fieldValue);
					Map<String,Long> lengthMap=measureLengthMapList.get(k);
					Long length = lengthMap.get(dimensionKey);
					if (length == null) {
						length = 1L;
					} else {
						length++;
					}
					lengthMap.put(dimensionKey, length);
				} else if ("count".equals(aggregateType)) {
					if (fieldValue == null) {
						fieldValue = new BigDecimal(0);
					}
					fieldValue = fieldValue.add(new BigDecimal(1));
					measureMap.put(dimensionKey, fieldValue);
				} else if ("min".equals(aggregateType)) {
					if (fieldValue == null) {
						measureMap.put(dimensionKey, new BigDecimal(measureValue + ""));
					} else if (new BigDecimal(measureValue + "").compareTo(fieldValue) < 0) {
						fieldValue = new BigDecimal(measureValue + "");
						measureMap.put(dimensionKey, fieldValue);
					}
				} else if ("max".equals(aggregateType)) {
					if (fieldValue == null) {
						measureMap.put(dimensionKey, new BigDecimal(measureValue + ""));
					} else if (new BigDecimal(measureValue + "").compareTo(fieldValue) > 0) {
						fieldValue = new BigDecimal(measureValue + "");
						measureMap.put(dimensionKey, fieldValue);
					}
				}
			}
		}
		for (int i = 0; i < measureList.size(); i++) {
			ReportDataItemDef reportDataItemDef = measureList.get(i);
			if (reportDataItemDef.getAggregateType().equals("average")) {
				Map<String, BigDecimal> dataMap = measureMapList.get(i);
				Map<String, Long> lengthMap = measureLengthMapList.get(i);
				Iterator<Map.Entry<String, BigDecimal>> it = dataMap.entrySet().iterator();
				while (it.hasNext()) {
					Map.Entry<String, BigDecimal> entry = it.next();
					long length = lengthMap.get(entry.getKey());
					if (length > 0) {
						dataMap.put(entry.getKey(), entry.getValue().divide(new BigDecimal(length)));
					}
				}
			}
		}
		
		int rows=1;
		for(int i=0;i<dimensionRowValueListList.size();i++) {
			rows*=dimensionRowValueListList.get(i).size();
		}
		for(int i=0;i<rows;i++) {
			List<Object> rowList=new ArrayList<Object>();
			returnList.add(rowList);
		}
		
		for(int i=0;i<dimensionRowValueListList.size();i++) {
			List<Object> dimensionValueList=dimensionRowValueListList.get(i);
			int size=rows/dimensionValueList.size();
			for(int j=0;j<size;j++) {
				for(int k=0;k<dimensionValueList.size();k++) {
					int index=j*dimensionValueList.size()+k;
					 List<Object> rowList=returnList.get(index);
				     rowList.add(dimensionValueList.get(k));
				}
			}
		}
		
		for(int i=dimensionRowValueListList.size()-1;i>=0;i--) {
			final int col=i;
			returnList.sort(new Comparator<List<Object>>() {

				@Override
				public int compare(List<Object> o1, List<Object> o2) {
					// TODO Auto-generated method stub
					Object value1=o1.get(col);
					Object value2=o2.get(col);
					if(value1 instanceof String) {
						return ((String)value1).compareTo((String)value2);
					}else if(value1 instanceof Long) {
						return ((Long)value1).compareTo((Long)value2);
					}
					return 0;
				}
				
			});
		}
		
		List<List<Object>> colHeaderListList=new ArrayList<List<Object>>();
		rows=1;
		for(int i=0;i<dimensionColValueListList.size();i++) {
			rows*=dimensionColValueListList.get(i).size();
		}
		for(int i=0;i<rows;i++) {
			List<Object> rowList=new ArrayList<Object>();
			colHeaderListList.add(rowList);
		}
		
		for(int i=0;i<dimensionColValueListList.size();i++) {
			List<Object> dimensionValueList=dimensionColValueListList.get(i);
			int size=rows/dimensionValueList.size();
			for(int j=0;j<size;j++) {
				for(int k=0;k<dimensionValueList.size();k++) {
					int index=j*dimensionValueList.size()+k;
					 List<Object> rowList=colHeaderListList.get(index);
				     rowList.add(dimensionValueList.get(k));
				}
			}
		}
		
		for(int i=dimensionColValueListList.size()-1;i>=0;i--) {
			final int col=i;
			colHeaderListList.sort(new Comparator<List<Object>>() {

				@Override
				public int compare(List<Object> o1, List<Object> o2) {
					// TODO Auto-generated method stub
					Object value1=o1.get(col);
					Object value2=o2.get(col);
					if(value1 instanceof String) {
						return ((String)value1).compareTo((String)value2);
					}else if(value1 instanceof Long) {
						return ((Long)value1).compareTo((Long)value2);
					}
					return 0;
				}
			});
		}
		
		for(int i=colHeaderListList.get(0).size()-1;i>=0;i--) {
			int size=colHeaderListList.size();
			List<Object> rowList=new ArrayList<Object>();
			for(int j=0;j<dimensionRowList.size();j++) {
				rowList.add(null);
			}
			returnList.add(0,rowList);
			for(int j=0;j<size;j++) {
				for(int k=0;k<measureList.size();k++) {
					rowList.add(colHeaderListList.get(j).get(i));
				}
			}
			
		}
		
	    int startRow=dimensionColList.size();
	    int endRow=returnList.size();
	    int startCol=dimensionRowList.size();
	    int endCol=returnList.get(0).size();
	    for(int i=startRow;i<endRow;i++) {
	    	List<Object> rowList=returnList.get(i);
	    	StringBuilder dimensionRowKeyBuilder=new StringBuilder();
	    	for(int j=0;j<dimensionRowList.size();j++) {
	    		if(j>0) {
	    			dimensionRowKeyBuilder.append("::");
	    		}
	    		dimensionRowKeyBuilder.append(rowList.get(j));
	    	}
	    	String dimensionRowKey=dimensionRowKeyBuilder.toString();
	    	for(int j=startCol;j<endCol;j+=measureList.size()) {
	    		StringBuilder dimensionColKeyBuilder=new StringBuilder();
	    		for(int k=0;k<dimensionColList.size();k++) {
	    			dimensionColKeyBuilder.append("::");
	    			dimensionColKeyBuilder.append(returnList.get(k).get(j));
	    		}
	    		String dimensionColKey=dimensionColKeyBuilder.toString();
	    		for(int k=0;k<measureList.size();k++) {
	    			Map<String,BigDecimal> measureMap=measureMapList.get(k);
	    			BigDecimal value=measureMap.get(dimensionRowKey+dimensionColKey);
	    			rowList.add(value);
	    		}
	    	}
	    }
	  
		for(int i=startRow;i<endRow;i++) {
			if(returnList.size()<=i) {
				break;
			}
			List<Object> rowList=returnList.get(i);
			boolean isNullRow=true;
			for(int j=startCol;j<rowList.size();j++) {
				if(rowList.get(j)!=null) {
					isNullRow=false;
					break;
				}
			}
			if(isNullRow) {
				returnList.remove(i);
				i--;
			}
		}
		
		for(int i=startCol;i<endCol;i++) {
			if(returnList.get(0).size()<=i) {
				break;
			}
			boolean isNullCol=true;
			for(int j=startRow;j<endRow;j++) {
				if(returnList.get(j).get(i)!=null) {
					isNullCol=false;
					break;
				}
			}
			if(isNullCol) {
				for(int j=0;j<endRow;j++) {
					returnList.get(j).remove(i);
					i--;
				}
			}
		}
		
        Table table=tableStore.get(summaryReport.getDataSourceConfig().getTableName());
		
		List<List<SelectItem>> selectItemListList = new ArrayList<List<SelectItem>>();
		for(int j=0;j<dimensionRowList.size();j++) {
			String field=dimensionRowList.get(j).getField();
			List<SelectItem> selectItemList=getSelectItemListByField(yunContext, table, field);
			if(selectItemList!=null) {
				selectItemListList.add(selectItemList);
			}else {
				selectItemListList.add(null);
			}
		}
		
		for(int i=startRow;i<returnList.size();i++) {
			List<Object> rowList=returnList.get(i);
			for(int j=0;j<dimensionRowValueListList.size();j++) {
				List<SelectItem> selectItemList=selectItemListList.get(j);
				if(selectItemList!=null) {
					for(int k=0;k<selectItemList.size();k++) {
						if(selectItemList.get(k).getValue().equals(rowList.get(j))) {
							rowList.set(j, selectItemList.get(k).getName());
							break;
						}
					}
				}
			}
		}
		
		List<Integer> mergeRowIndexList=new ArrayList<Integer>();
		List<Integer> mergeRowCountList=new ArrayList<Integer>();
		List<Map<Integer,Integer>> mergeRowMapList=new  ArrayList<Map<Integer,Integer>>();
		List<Map<Integer,String>> inVisibleRowMapList=new  ArrayList<Map<Integer,String>>();
		for(int i=0;i<dimensionRowValueListList.size();i++) {
			mergeRowIndexList.add(startRow);
			mergeRowCountList.add(1);
			Map<Integer,Integer> mergeRowMap=new HashMap<Integer,Integer>();
			mergeRowMap.put(startRow,1);
			mergeRowMapList.add(mergeRowMap);
			inVisibleRowMapList.add(new HashMap<Integer,String>());
		}
		for(int i=startRow+1;i<returnList.size();i++) {
			List<Object> previousRowList=returnList.get(i-1);
			List<Object> rowList=returnList.get(i);
			for(int j=dimensionRowValueListList.size()-1;j>=0;j--) {
				Integer mergeRowIndex=mergeRowIndexList.get(j);
				Integer mergeRowCount=mergeRowCountList.get(j);
				Map<Integer,Integer> mergeRowMap=mergeRowMapList.get(j);
				Map<Integer,String> inVisibleRowMap=inVisibleRowMapList.get(j);
				boolean isEqual=false;
				if(((String)rowList.get(j)).compareTo((String)previousRowList.get(j))==0){
					if(j>0) {
						int previousCol=j-1;
						if(((String)rowList.get(previousCol)).compareTo((String)previousRowList.get(previousCol))==0){
							isEqual=true;
						}
					}else {
						isEqual=true;
					}
				}
				if(isEqual) {
					mergeRowCount++;
					mergeRowCountList.set(j, mergeRowCount);
					mergeRowMap.put(mergeRowIndex, mergeRowCount);
					inVisibleRowMap.put(i, "invisible");
				}else {
					mergeRowIndexList.set(j, i);
					mergeRowCountList.set(j, 1);
					mergeRowMap.put(i, 1);
				}
			}
		}
			
		List<List<SelectItem>> selectItemColListList = new ArrayList<List<SelectItem>>();
		for(int j=0;j<dimensionColList.size();j++) {
			String field=dimensionColList.get(j).getField();
			List<SelectItem> selectItemList=getSelectItemListByField(yunContext, table, field);
			if(selectItemList!=null) {
				selectItemColListList.add(selectItemList);
			}else {
				selectItemColListList.add(null);
			}
		}
		
		for (int i = 0; i < startRow; i++) {
			List<Object> rowList = returnList.get(i);
			List<SelectItem> selectItemList = selectItemColListList.get(i);
			if (selectItemList != null) {
				for(int j=startCol;j<endCol;j++) {
					for (int k = 0; k < selectItemList.size(); k++) {
						if (selectItemList.get(k).getValue().equals(rowList.get(j))) {
							rowList.set(j, selectItemList.get(k).getName());
							break;
						}
					}
				}
			}
		}
		

		List<Integer> mergeColIndexList=new ArrayList<Integer>();
		List<Integer> mergeColCountList=new ArrayList<Integer>();
		List<Map<Integer,Integer>> mergeColMapList=new  ArrayList<Map<Integer,Integer>>();
		List<Map<Integer,String>> inVisibleColMapList=new  ArrayList<Map<Integer,String>>();
		for(int i=0;i<dimensionColValueListList.size();i++) {
			mergeColIndexList.add(startCol);
			mergeColCountList.add(1);
			Map<Integer,Integer> mergeColMap=new HashMap<Integer,Integer>();
			mergeColMap.put(startCol,1);
			mergeColMapList.add(mergeColMap);
			inVisibleColMapList.add(new HashMap<Integer,String>());
		}
		for(int i=0;i<startRow;i++) {
			List<Object> rowList=returnList.get(i);
			for(int j=startCol+1;j<endCol;j++) {
				Integer mergeColIndex=mergeColIndexList.get(i);
				Integer mergeColCount=mergeRowCountList.get(i);
				Map<Integer,Integer> mergeColMap=mergeColMapList.get(i);
				Map<Integer,String> inVisibleColMap=inVisibleColMapList.get(i);
				
				boolean isEqual=false;
				if(((String)rowList.get(j)).compareTo((String)rowList.get(j-1))==0){
					if(i>0) {
						List<Object> previousRowList=returnList.get(i-1);
						if(((String)previousRowList.get(j)).compareTo((String)previousRowList.get(j-1))==0){
							isEqual=true;
						}
					}else {
						isEqual=true;
					}
				}
				if(isEqual) {
					mergeColCount++;
					mergeColCountList.set(i, mergeColCount);
					mergeColMap.put(mergeColIndex, mergeColCount);
					inVisibleColMap.put(j, "invisible");
				}else {
					mergeColIndexList.set(i, j);
					mergeColCountList.set(i, 1);
					mergeColMap.put(j, 1);
				}
			}
		}

		SummaryReportModel summaryReportModel=new SummaryReportModel();
		List<SummaryReportRow> summaryReportRowList=new ArrayList<SummaryReportRow>();
		summaryReportModel.setSummaryReportRowList(summaryReportRowList);
		
		for(int i=0;i<startRow;i++) {
			List<Object> rowList=returnList.get(i);
			Map<Integer,Integer> mergeColMap=mergeColMapList.get(i);
			Map<Integer,String> inVisibleColMap=inVisibleColMapList.get(i);
			SummaryReportRow summaryReportRow=new SummaryReportRow();
			summaryReportRowList.add(summaryReportRow);
			List<SummaryReportCell> cellList=new ArrayList<SummaryReportCell>();
			summaryReportRow.setSummaryReportCellList(cellList);
			for(int j=0;j<endCol;j++) {
				if(j<startCol) {
					SummaryReportCell cell=new SummaryReportCell();
					cellList.add(cell);
					cell.setValue("");
				}else {
					SummaryReportCell cell=new SummaryReportCell();
					cellList.add(cell);
					cell.setValue(rowList.get(j));
				
					Integer colspan=mergeColMap.get(j);
					if(colspan!=null) {
						cell.setColspan(colspan);
					}
					if(inVisibleColMap.get(j)!=null) {
						cell.setDisplay(false);
					}
				}
			}
		}
		
		for(int i=startRow;i<returnList.size();i++) {
			List<Object> rowList=returnList.get(i);
			SummaryReportRow summaryReportRow=new SummaryReportRow();
			summaryReportRowList.add(summaryReportRow);
			List<SummaryReportCell> cellList=new ArrayList<SummaryReportCell>();
			summaryReportRow.setSummaryReportCellList(cellList);
			for(int j=0;j<dimensionRowList.size();j++) {
				Map<Integer,Integer> mergeRowMap=mergeRowMapList.get(j);
				Map<Integer,String> inVisibleRowMap=inVisibleRowMapList.get(j);
				SummaryReportCell cell=new SummaryReportCell();
				cellList.add(cell);
				cell.setValue(rowList.get(j));
				
				
				Integer rowspan=mergeRowMap.get(i);
				if(rowspan!=null) {
					cell.setRowspan(rowspan);
				}
				if(inVisibleRowMap.get(i)!=null) {
					cell.setDisplay(false);
				}
			}
			for(int j=dimensionRowList.size();j<rowList.size();j++) {
				SummaryReportCell cell=new SummaryReportCell();
				cellList.add(cell);
				cell.setValue(rowList.get(j));
			}
		}
		return summaryReportModel;
	}
	
	private SummaryReportModel  getGroupReportData(YunContext yunContext,SummaryReport summaryReport,List<Map<String,Object>> dataList){
		List<List<Object>> returnList=new ArrayList<List<Object>>();
		List<List<Object>> dimensionValueListList=new ArrayList<List<Object>>();
		List<Map<String,BigDecimal>> measureMapList=new ArrayList<Map<String,BigDecimal>>();
		List<Map<String,Long>> measureLengthMapList=new ArrayList<Map<String,Long>>();
		List<ReportDataItemDef> dimensionRowList=summaryReport.getDimensionRowList();
		for(int i=0;i<dimensionRowList.size();i++) {
			dimensionValueListList.add(new ArrayList<Object>());
		}
		List<ReportDataItemDef> measureList=summaryReport.getMeasureList();
		for(int i=0;i<measureList.size();i++) {
			measureMapList.add(new HashMap<String,BigDecimal>());
			measureLengthMapList.add(new HashMap<String,Long>());
		}
		for(int i=0;i<dataList.size();i++) {
			Map<String,Object> dataMap=dataList.get(i);
			StringBuilder dimensionKeyBuilder=new StringBuilder();
			for(int j=0;j<dimensionRowList.size();j++) {
				if (j > 0) {
					dimensionKeyBuilder.append("::");
				}
				ReportDataItemDef reportDataItemDef=dimensionRowList.get(j);
				String field=reportDataItemDef.getField();
				Object dimensionValue=dataMap.get(field);
				String fieldExtra = reportDataItemDef.getFieldExtra();
				if (!StringUtils.isJsonEmpty(fieldExtra)) {
					Date dateValue = (Date) dimensionValue;
					if ("year".equals(fieldExtra)) {
						dimensionValue = new SimpleDateFormat("yyyy年").format(dateValue);
					} else if ("quarter".equals(fieldExtra)) {
						Calendar calendar = Calendar.getInstance();
						calendar.setTime(dateValue);
						StringBuilder dimensionValueBuilder = new StringBuilder();
						int year = calendar.get(Calendar.YEAR);
						dimensionValueBuilder.append(year);
						dimensionValueBuilder.append("年");
						int month = calendar.get(Calendar.MONTH);
						if (month >= 0 && month <= 2) {
							dimensionValueBuilder.append("第一季度");
						} else if (month >= 3 && month <= 5) {
							dimensionValueBuilder.append("第二季度");
						} else if (month >= 6 && month <= 8) {
							dimensionValueBuilder.append("第三季度");
						} else if (month >= 9 && month <= 11) {
							dimensionValueBuilder.append("第四季度");
						}
						dimensionValue = dimensionValueBuilder.toString();
					} else if ("month".equals(fieldExtra)) {
						dimensionValue = new SimpleDateFormat("yyyy年MM月").format(dateValue);
					} else if ("day".equals(fieldExtra)) {
						dimensionValue = new SimpleDateFormat("yyyy-MM-dd").format(dateValue);
					}
				}
				dimensionKeyBuilder.append(dimensionValue);
				List<Object> dimensionValueList = dimensionValueListList.get(j);
				if (!dimensionValueList.contains(dimensionValue)) {
					dimensionValueList.add(dimensionValue);
				}
			}
			String dimensionKey=dimensionKeyBuilder.toString();
			for(int k=0;k<measureList.size();k++) {
				ReportDataItemDef reportDataItemDef=measureList.get(k);
				String measureField = reportDataItemDef.getField();
				Object measureValue = dataMap.get(measureField);
				String aggregateType = reportDataItemDef.getAggregateType();
				Map<String,BigDecimal> measureMap=measureMapList.get(k);
				BigDecimal fieldValue = measureMap.get(dimensionKey);
				if ("sum".equals(aggregateType)) {
					if (fieldValue == null) {
						fieldValue = new BigDecimal(0);
					}
					fieldValue = fieldValue.add(new BigDecimal(measureValue + ""));
					measureMap.put(dimensionKey, fieldValue);
				} else if ("average".equals(aggregateType)) {
					if (fieldValue == null) {
						fieldValue = new BigDecimal(0);
					}
					fieldValue = fieldValue.add(new BigDecimal(measureValue + ""));
					measureMap.put(dimensionKey, fieldValue);
					Map<String,Long> lengthMap=measureLengthMapList.get(k);
					Long length = lengthMap.get(dimensionKey);
					if (length == null) {
						length = 1L;
					} else {
						length++;
					}
					lengthMap.put(dimensionKey, length);
				} else if ("count".equals(aggregateType)) {
					if (fieldValue == null) {
						fieldValue = new BigDecimal(0);
					}
					fieldValue = fieldValue.add(new BigDecimal(1));
					measureMap.put(dimensionKey, fieldValue);
				} else if ("min".equals(aggregateType)) {
					if (fieldValue == null) {
						measureMap.put(dimensionKey, new BigDecimal(measureValue + ""));
					} else if (new BigDecimal(measureValue + "").compareTo(fieldValue) < 0) {
						fieldValue = new BigDecimal(measureValue + "");
						measureMap.put(dimensionKey, fieldValue);
					}
				} else if ("max".equals(aggregateType)) {
					if (fieldValue == null) {
						measureMap.put(dimensionKey, new BigDecimal(measureValue + ""));
					} else if (new BigDecimal(measureValue + "").compareTo(fieldValue) > 0) {
						fieldValue = new BigDecimal(measureValue + "");
						measureMap.put(dimensionKey, fieldValue);
					}
				}
			}
		}
		for (int i = 0; i < measureList.size(); i++) {
			ReportDataItemDef reportDataItemDef = measureList.get(i);
			if (reportDataItemDef.getAggregateType().equals("average")) {
				Map<String, BigDecimal> dataMap = measureMapList.get(i);
				Map<String, Long> lengthMap = measureLengthMapList.get(i);
				Iterator<Map.Entry<String, BigDecimal>> it = dataMap.entrySet().iterator();
				while (it.hasNext()) {
					Map.Entry<String, BigDecimal> entry = it.next();
					long length = lengthMap.get(entry.getKey());
					if (length > 0) {
						dataMap.put(entry.getKey(), entry.getValue().divide(new BigDecimal(length)));
					}
				}
			}
		}
		int rows=1;
		for(int i=0;i<dimensionValueListList.size();i++) {
			rows*=dimensionValueListList.get(i).size();
		}
		for(int i=0;i<rows;i++) {
			List<Object> rowList=new ArrayList<Object>();
			returnList.add(rowList);
		}
		
		for(int i=0;i<dimensionValueListList.size();i++) {
			List<Object> dimensionValueList=dimensionValueListList.get(i);
			int size=rows/dimensionValueList.size();
			for(int j=0;j<size;j++) {
				for(int k=0;k<dimensionValueList.size();k++) {
					int index=j*dimensionValueList.size()+k;
					 List<Object> rowList=returnList.get(index);
				     rowList.add(dimensionValueList.get(k));
				}
			}
		}
		
		for(int i=0;i<returnList.size();i++) {
			StringBuilder dimensionKeyBuilder=new StringBuilder();
			List<Object> rowList=returnList.get(i);
			for(int j=0;j<dimensionValueListList.size();j++) {
				if(j>0) {
					dimensionKeyBuilder.append("::");
				}
				dimensionKeyBuilder.append(rowList.get(j));
			}
			String dimensionKey=dimensionKeyBuilder.toString();
			for(int j=0;j<measureList.size();j++) {
				Map<String, BigDecimal> dataMap = measureMapList.get(j);
				BigDecimal value=dataMap.get(dimensionKey);
				rowList.add(value);
			}
		}
		
		
		int len=rows;
		int startCol=dimensionValueListList.size();
		for(int i=0;i<len;i++) {
			if(returnList.size()<=i) {
				break;
			}
			List<Object> rowList=returnList.get(i);
			boolean isNullRow=true;
			for(int j=startCol;j<rowList.size();j++) {
				if(rowList.get(j)!=null) {
					isNullRow=false;
					break;
				}
			}
			if(isNullRow) {
				returnList.remove(i);
				i--;
			}
		}
		
		Table table=tableStore.get(summaryReport.getDataSourceConfig().getTableName());
		
		List<List<SelectItem>> selectItemListList = new ArrayList<List<SelectItem>>();
		for(int j=0;j<dimensionRowList.size();j++) {
			String field=dimensionRowList.get(j).getField();
			List<SelectItem> selectItemList=getSelectItemListByField(yunContext, table, field);
			if(selectItemList!=null) {
				selectItemListList.add(selectItemList);
			}else {
				selectItemListList.add(null);
			}
		}
		
		for(int i=0;i<returnList.size();i++) {
			List<Object> rowList=returnList.get(i);
			for(int j=0;j<dimensionValueListList.size();j++) {
				List<SelectItem> selectItemList=selectItemListList.get(j);
				if(selectItemList!=null) {
					for(int k=0;k<selectItemList.size();k++) {
						if(selectItemList.get(k).getValue().equals(rowList.get(j))) {
							rowList.set(j, selectItemList.get(k).getName());
							break;
						}
					}
				}
			}
		}
		for(int i=dimensionValueListList.size()-1;i>=0;i--) {
			final int col=i;
			returnList.sort(new Comparator<List<Object>>() {

				@Override
				public int compare(List<Object> o1, List<Object> o2) {
					// TODO Auto-generated method stub
					Object value1=o1.get(col);
					Object value2=o2.get(col);
					if(value1 instanceof String) {
						return ((String)value1).compareTo((String)value2);
					}else if(value1 instanceof Long) {
						return ((Long)value1).compareTo((Long)value2);
					}
					return 0;
				}
				
			});
		}
		
		List<Integer> mergeRowIndexList=new ArrayList<Integer>();
		List<Integer> mergeRowCountList=new ArrayList<Integer>();
		List<Map<Integer,Integer>> mergeRowMapList=new  ArrayList<Map<Integer,Integer>>();
		List<Map<Integer,String>> inVisibleMapList=new  ArrayList<Map<Integer,String>>();
		for(int i=0;i<dimensionValueListList.size();i++) {
			mergeRowIndexList.add(0);
			mergeRowCountList.add(1);
			Map<Integer,Integer> mergeRowMap=new HashMap<Integer,Integer>();
			mergeRowMap.put(0,1);
			mergeRowMapList.add(mergeRowMap);
			inVisibleMapList.add(new HashMap<Integer,String>());
		}
		for(int i=1;i<returnList.size();i++) {
			List<Object> previousRowList=returnList.get(i-1);
			List<Object> rowList=returnList.get(i);
			for(int j=dimensionValueListList.size()-1;j>=0;j--) {
				Integer mergeRowIndex=mergeRowIndexList.get(j);
				Integer mergeRowCount=mergeRowCountList.get(j);
				Map<Integer,Integer> mergeRowMap=mergeRowMapList.get(j);
				Map<Integer,String> inVisibleMap=inVisibleMapList.get(j);
				boolean isEqual=false;
				if(((String)rowList.get(j)).compareTo((String)previousRowList.get(j))==0){
					if(j>0) {
						int previousCol=j-1;
						if(((String)rowList.get(previousCol)).compareTo((String)previousRowList.get(previousCol))==0){
							isEqual=true;
						}
					}else {
						isEqual=true;
					}
				}
				if(isEqual) {
					mergeRowCount++;
					mergeRowCountList.set(j, mergeRowCount);
					mergeRowMap.put(mergeRowIndex, mergeRowCount);
					inVisibleMap.put(i, "invisible");
				}else {
					mergeRowIndexList.set(j, i);
					mergeRowCountList.set(j, 1);
					mergeRowMap.put(i, 1);
				}
			}
		}
		
		SummaryReportModel summaryReportModel=new SummaryReportModel();
		List<SummaryReportRow> summaryReportRowList=new ArrayList<SummaryReportRow>();
		summaryReportModel.setSummaryReportRowList(summaryReportRowList);
		
		SummaryReportRow headerRow=new SummaryReportRow();
		summaryReportRowList.add(headerRow);
		List<SummaryReportCell> headerCellList=new ArrayList<SummaryReportCell>();
		headerRow.setSummaryReportCellList(headerCellList);
		for(int i=0;i<dimensionRowList.size();i++) {
			ReportDataItemDef reportDataItemDef=dimensionRowList.get(i);
			String field=reportDataItemDef.getField();
			Column column=table.getColumnByColumnName(field);
			SummaryReportCell cell=new SummaryReportCell();
			cell.setValue(column.getName());
			headerCellList.add(cell);
		}
		for(int i=0;i<measureList.size();i++) {
			ReportDataItemDef reportDataItemDef=measureList.get(i);
			String field=reportDataItemDef.getField();
			Column column=table.getColumnByColumnName(field);
			SummaryReportCell cell=new SummaryReportCell();
			cell.setValue(column.getName());
			headerCellList.add(cell);
		}
		
		for(int i=0;i<returnList.size();i++) {
			List<Object> rowList=returnList.get(i);
			SummaryReportRow summaryReportRow=new SummaryReportRow();
			summaryReportRowList.add(summaryReportRow);
			List<SummaryReportCell> cellList=new ArrayList<SummaryReportCell>();
			summaryReportRow.setSummaryReportCellList(cellList);
			for(int j=0;j<dimensionRowList.size();j++) {
				Map<Integer,Integer> mergeRowMap=mergeRowMapList.get(j);
				Map<Integer,String> inVisibleMap=inVisibleMapList.get(j);
				SummaryReportCell cell=new SummaryReportCell();
				cellList.add(cell);
				cell.setValue(rowList.get(j));
				Integer rowspan=mergeRowMap.get(i);
				if(rowspan!=null) {
					cell.setRowspan(rowspan);
				}
				if(inVisibleMap.get(i)!=null) {
					cell.setDisplay(false);
				}
			}
			for(int j=dimensionRowList.size();j<rowList.size();j++) {
				SummaryReportCell cell=new SummaryReportCell();
				cellList.add(cell);
				cell.setValue(rowList.get(j));
			}
		}
		return summaryReportModel;
	}
	
	private List<SelectItem> getSelectItemListByField(YunContext yunContext,Table table,String field){
		Column column = table.getColumnByColumnName(field);
		LookupInfo lookupInfo = column.getLookupInfo();
		if (lookupInfo != null) {
			List<SelectItem> selectItemList = lookupUtil.getSelectItemList(yunContext, lookupInfo);
			return selectItemList;
		}
		return null;
	}
	
	private ReportDataItemDef parseReportDataItemDefObjectNode(ObjectNode objectNode) {
		ReportDataItemDef reportDataItemDef=new ReportDataItemDef();
		JsonNode jsonNode=objectNode.get("field");
		if(jsonNode!=null) {
			reportDataItemDef.setField(jsonNode.asText());
		}
		jsonNode=objectNode.get("fieldExtra");
		if(jsonNode!=null) {
			reportDataItemDef.setFieldExtra(jsonNode.asText());
		}
		jsonNode=objectNode.get("aggregateType");
		if(jsonNode!=null) {
			reportDataItemDef.setAggregateType(jsonNode.asText());
		}
		return reportDataItemDef;
	}
	
	private DataSourceConfig buildDataSourceConfig(ObjectNode objectNode) {
		DataSourceConfig dataSourceConfig = new DataSourceConfig();
		String id = objectNode.get("dataSourceConfigPage").get("id").asText();
		String name = objectNode.get("dataSourceConfigPage").get("name").asText();
		String tableName = objectNode.get("dataSourceConfigPage").get("tableName").asText();
		JsonNode jsonNode=objectNode.get("dataSourceConfigPage").get("whereClause");
		String whereClause=null;
		if(jsonNode!=null) {
			whereClause=jsonNode.asText();
		}
		String orderBy=null;
		jsonNode=objectNode.get("dataSourceConfigPage").get("orderBy");
		if(jsonNode!=null) {
			orderBy=jsonNode.asText();
		}
		dataSourceConfig.setId(id);
		dataSourceConfig.setName(name);
		dataSourceConfig.setTableName(tableName);
		if (!StringUtils.isEmpty(whereClause)) {
			Expression expression = ExpressionUtil.convertToExpression(whereClause,
					Expression.EXPRESSION_TYPE_JAVASCRIPT);
			dataSourceConfig.setWhereClause(expression);
		}
		dataSourceConfig.setOrderBy(orderBy);
		return dataSourceConfig;
	}
	
	private TableData getTableData(YunContext yunContext, SummaryReport summaryReport) {
		DataSourceConfig dataSourceConfig = summaryReport.getDataSourceConfig();
		Query query = new Query();
		Expression whereClauseExpression=dataSourceConfig.getWhereClause();
		if(whereClauseExpression!=null) {
			String whereClause=javaScriptScriptService.eval(whereClauseExpression.getScript(), yunContext.getVarValueMap());
			if(!StringUtils.isEmpty(whereClause)) {
				query.add(Restrictions.sql(whereClause));
			}
		}
		Page page=yunContext.getPage();
		if(page!=null) {
			List<IDataBinding> searchDataBindingList=page.getAttribute("key_search_field_list");
			if(searchDataBindingList!=null) {
				for(int i=0;i<searchDataBindingList.size();i++) {
					IDataBinding dataBinding=searchDataBindingList.get(i);
					Object value=variableService.getVariableValue(yunContext, ((IVarName)dataBinding).getVarName());
					if(value!=null) {
						String field=null;
						String op=null;
						String fieldInfos=page.getPageContext("field_"+dataBinding.getDataField());
						if(!StringUtils.isEmpty(fieldInfos)) {
							String fieldInfoArray[]=fieldInfos.split("[|]");
							field=fieldInfoArray[0];
							op=fieldInfoArray[1];
						}else {
							field=dataBinding.getDataField();
							op="=";
						}
						if(op.equals("=")) {
							query.add(Restrictions.eq(field, value));
						}else if(op.equals(">")) {
							query.add(Restrictions.gt(field, value));
						}else if(op.equals(">=")) {
							query.add(Restrictions.ge(field, value));
						}else if(op.equals("<")) {
							query.add(Restrictions.lt(field, value));
						}else if(op.equals("<=")) {
							query.add(Restrictions.le(field, value));
						}
					}
				}
			}
		}
		Table table = tableStore.get(dataSourceConfig.getTableName());
		IDataSource dataSource = dataSourceStore.getDataSource(table.getAccessType());
		TableData tableData = dataSource.select(yunContext, table, query);
		
		return tableData;
	}
}
